package com.sunkyc.framework.aop.req;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sunkyc.commons.entity.R;
import com.sunkyc.framework.mq.loginmq.DisruptorMqService;
import com.sunkyc.framework.mq.reqmq.ReqDisruptorMqService;
import com.sunkyc.framework.system.entity.LoginUser;
import com.sunkyc.framework.system.entity.SysLoginLog;
import com.sunkyc.framework.system.entity.SysReqLog;
import com.sunkyc.framework.utils.IpUtils;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Component
@Aspect
public class RequestAspect {
    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();
    @Pointcut("@annotation(com.sunkyc.commons.annotation.ReqLog)")
    public void annotationAspect() {

    }

    @Before("annotationAspect()")
    public void doBefore(){
        threadLocal.set(System.currentTimeMillis());
    }



    @AfterReturning(pointcut = "annotationAspect()", returning = "obj")
    public void doAfter(JoinPoint joinPoint, Object obj) throws Throwable {
        setLog(joinPoint,obj,null);
    }

    @AfterThrowing(pointcut = "annotationAspect()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        Object[] args = joinPoint.getArgs();
        log.error(e.getMessage());
        setLog(joinPoint,null,e);
    }


    private void setLog(JoinPoint joinPoint, Object obj, Throwable e) {
        Object[] args = joinPoint.getArgs();
        List<String> argList = new ArrayList<>();
        for (Object arg : args) {
            if(BeanUtil.isNotEmpty(arg)){
                argList.add(StringUtils.replace(JSONUtil.parseObj(arg).toString(), "\"", ""));
            }
        }
        R r = null;
        SysReqLog sysReqLog = null;
        if (obj instanceof R) {
            r = (R) obj;
        }
        if (ObjectUtil.isNotNull(r)) {
            sysReqLog = buildLog(joinPoint);

            if(CollectionUtil.isNotEmpty(argList)){
                sysReqLog.setReqParams(argList.toString().replaceAll("\\[","").replaceAll("\\]",""));
            }
            sysReqLog.setReqResult(r.getMsg());
            sysReqLog.setReqState("0");
            sysReqLog.setResTime(System.currentTimeMillis()-threadLocal.get());
            sysReqLog.setCreateBy(StpUtil.getLoginIdAsLong());
        }

        if(ObjectUtil.isNotNull(e)){
            sysReqLog = buildLog(joinPoint);
            if(CollectionUtil.isNotEmpty(argList)){
                sysReqLog.setReqParams(argList.toString());
            }
            sysReqLog.setResTime(System.currentTimeMillis()-threadLocal.get());
            sysReqLog.setReqState("1");
            sysReqLog.setCreateBy(StpUtil.getLoginIdAsLong());
            sysReqLog.setReqResult("操作失败");
            sysReqLog.setErrParams(e.getMessage());
        }
        // 此处必须释放，不然堆积会造成系统危险
        threadLocal.remove();
        ReqDisruptorMqService disruptorMqService = SpringUtil.getBean(ReqDisruptorMqService.class);
        disruptorMqService.sendMessage(JSONUtil.toJsonStr(sysReqLog));

    }
    private SysReqLog buildLog(JoinPoint joinPoint) {
        // 获取登录参数
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        // ip地点
        String place = IpUtils.getIpAddress(request);
        // 地址
        String address = IpUtils.getIpSource(place);
        // 浏览器
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        Browser browser = userAgent.getBrowser();
        // 操作系统
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();
        SysReqLog rlog = new SysReqLog();
        rlog.setReqId(IdUtil.getSnowflakeNextIdStr())
                .setBrowerName(browser.getName())
                .setIpAddr(place)
                .setReqTime(LocalDateTime.now())
                .setReqMethod(request.getMethod())
                .setIpSources(address)
                .setReqInter(joinPoint.getTarget().getClass().getName()+"->"+joinPoint.getSignature().getName())
                .setSystemName(operatingSystem.getName());
        return rlog;

    }

}
